local Tf_TOOL = require("tf_registerimages")

--==============================
--[[ 太阳炸蛋buff相关函数 ]]
--==============================
local function AfterWorking(inst, data)
    if
        data.target and
        data.target.components.workable ~= nil and
        data.target.components.workable:CanBeWorked()
    then
        -- TIP：事件机制会在发送者那边逻辑当前帧就处理完的。所以这里只需要设置关键变量 workleft=0 即可
        data.target.components.workable.workleft = 0
    end
end

--==============================
--[[ 章鱼小丸子buff相关函数 ]]
--==============================
local function CheckValidAttackData(attacker, data)
    if data then
        if data.projectile and data.projectile.components.projectile and data.projectile.components.projectile:IsBounced() then
            -- bounced projectiles don't count
            return false
        elseif data.weapon and data.weapon.components.inventoryitem == nil then
            -- fake "weapons" used for detached aoe dmg don't count (e.g. flamethrower_fx)
            return false
        end
    end
    return true
end
local function AfterAttack(attacker, data)
    if CheckValidAttackData(attacker, data) then
        attacker.components.sanity:DoDelta(TUNING.BATTLESONG_SANITYGAIN_DELTA)
    end
end

--==============================
--[[ 沙拉酱buff相关函数 ]]
--==============================
local function OnTick(inst, target)
    if target.components.health ~= nil and
        not target.components.health:IsDead() and
        not target:HasTag("playerghost") then
        target.components.health:DoDelta(TUNING.JELLYBEAN_TICK_VALUE, nil, "tf_buff_dressing")
    else
        inst.components.debuff:Stop()
    end
end

--==============================
--[[ 培根碎buff相关函数 ]]
--==============================
local function IsLifeDrainable(target)
    return not target:HasAnyTag(NON_LIFEFORM_TARGET_TAGS) or target:HasTag("lifedrainable")
end

local function tf_bacon_bits(owner, data)
    -- 生命吸取
    if data ~= nil and data.damageresolved ~= nil and data.damageresolved > 0 then
        local health_steal_value = data.damageresolved * 0.065
        if owner.components.health and owner.components.health:IsHurt() and IsLifeDrainable(data.target) then
            owner.components.health:DoDelta(health_steal_value, false, "tf_buff_bacon_bits")
        end
    end
end

--==============================
--[[ 草莓酱buff相关函数 ]]
--==============================
local spdamage = {
    planar = 20,
}
local function strawberry_jam(owner, data)
    -- 范围伤害
    -- 根据有无启用PvP,排除玩家标签
    local target = data.target
    if target == nil or data.weapon == nil then
        return
    end
    local fx = SpawnPrefab("slingshotammo_gunpowder_explode")
    if fx ~= nil then
        fx.Transform:SetPosition(target.Transform:GetWorldPosition())
    end
    target.components.combat:GetAttacked(data.weapon or target, 0, nil, nil, spdamage)

    local friendlyTags = Tf_TOOL.TagsFriendly(TheNet:GetPVPEnabled() and {} or { "player" })
    local x, y, z = target.Transform:GetWorldPosition()
    -- 查找范围4加上物理半径内的所有实体，排除友好单位
    local entities = TheSim:FindEntities(x, y, z, 4, nil, friendlyTags)
    for _, entity in ipairs(entities) do
        if entity ~= owner and entity ~= target and entity.components.combat then
            entity.components.combat:GetAttacked(data.weapon or target, 0, nil, nil, spdamage)
            if entity.components.health and entity.components.health:IsDead() then
                owner:PushEvent("killed", { victim = entity, attacker = owner })
                if entity.components.combat.onkilledbyother ~= nil then
                    entity.components.combat.onkilledbyother(entity, owner)
                end
            end
        end
    end
end

--==============================
--[[ 橘子酱buff相关函数 ]]
--==============================
local function no_aggro(attacker, target)
    local targets_target = target.components.combat ~= nil and target.components.combat.target or nil
    return targets_target ~= nil and targets_target:IsValid() and targets_target ~= attacker and attacker ~= nil and attacker:IsValid()
        and (GetTime() - target.components.combat.lastwasattackedbytargettime) < 4
        and (targets_target.components.health ~= nil and not targets_target.components.health:IsDead())
end

local MAX_JAM_VARIATIONS = 7
local MAX_PICK_INDEX = 3
local JAM_VAR_POOL = { 1 }
for i = 2, MAX_JAM_VARIATIONS do
    table.insert(JAM_VAR_POOL, math.random(i), i)
end

local function PickOrangeJam()
    local rand = table.remove(JAM_VAR_POOL, math.random(MAX_PICK_INDEX))
    table.insert(JAM_VAR_POOL, rand)
    return rand
end

local function TrySpawnOrangeJam(target, min_scale, max_scale, duration)
    local x, y, z = target.Transform:GetWorldPosition()
    if TheWorld.Map:IsPassableAtPoint(x, 0, z) then
        local fx = SpawnPrefab("honey_trail")
        fx.Transform:SetPosition(x, 0, z) -- NOTES(JBK): This must be before SetVariation is called!
        fx:SetVariation(PickOrangeJam(), GetRandomMinMax(min_scale, max_scale), duration + math.random() * .5)
    elseif TheWorld.has_ocean then
        SpawnPrefab("ocean_splash_ripple" .. tostring(math.random(2))).Transform:SetPosition(x, 0, z)
    end
end

local function OnUpdate_OrangeJam(target, t0)
    local elapsed = GetTime() - t0
    if elapsed < 8 then
        local k = 1 - elapsed / 8
        k = k * k * 0.6 + 0.3
        TrySpawnOrangeJam(target, k, k + 0.2, 2)
    else
        target._orange_jamtask:Cancel()
        target._orange_jamtask = nil
        target:RemoveTag("orange_jam_afflicted")
        if target.components.locomotor then
            target.components.locomotor:RemoveExternalSpeedMultiplier(target, "orange_jam_afflicted")
        end
        target:PushEvent("stop_orange_jam_afflicted")
    end
end

local function OnHit_OrangeJam(attacker, data)
    local target = data.target
    if target and target:IsValid() then
        if target:HasTag("orange_jam_afflicted") then
            if data.damage ~= nil and data.damage > 0 then
                local damage = data.damage
                local truedamage = damage * 0.3
                if target.components.health ~= nil and not target:HasTag("playerghost") then
                    target.components.health:DoDelta(-truedamage, nil, "orange_jam_afflicted", nil, attacker, true) -- 无视防御
                end
                if target.components.health:IsDead() then
                    attacker:PushEvent("killed", { victim = target })
                    if target.components.combat ~= nil and target.components.combat.onkilledbyother ~= nil then
                        target.components.combat.onkilledbyother(target, attacker)
                    end
                end
            end
        end
        local pushstartevent
        if target._orange_jamtask then
            target._orange_jamtask:Cancel()
        else
            target:AddTag("orange_jam_afflicted")
            if target.components.locomotor and not target:HasAnyTag("flying", "playerghost") then
                target.components.locomotor:SetExternalSpeedMultiplier(target, "orange_jam_afflicted", 0.2)
            end
            pushstartevent = true
        end
        target._orange_jamtask = target:DoPeriodicTask(1, OnUpdate_OrangeJam, 0.43, GetTime())

        if not no_aggro(attacker, target) and target.components.combat then
            target:PushEvent("attacked", { attacker = attacker, damage = 0, weapon = data.weapon })
        end

        if pushstartevent then
            target:PushEvent("start_orange_jam_afflicted")
        end
    end
end

--==============================
--[[ buff列表 ]]
--==============================
local buffs = {
    -- 太阳炸蛋
    ssu_egg = {
        duration = TUNING.TOTAL_DAY_TIME,     -- buff时长
        priority = 1,                         -- 优先级
        onattachedfn = function(inst, target) -- buff触发的执行函数
            target:ListenForEvent("working", AfterWorking)
        end,
        -- onextendedfn = function (inst,target) -- buff存在期间，添加了相同buff的执行函数
        -- end,
        ondetachedfn = function(inst, target) -- buff结束时的执行函数
            target:RemoveEventCallback("working", AfterWorking)
        end,
    },
    -- 跳跳糖
    popping_candy = {
        duration = TUNING.TOTAL_DAY_TIME,     -- buff时长
        priority = 1,                         -- 优先级
        onattachedfn = function(inst, target) -- buff触发的执行函数
            -- see wormlight.lua for original code
            if target.wormlight ~= nil then
                if target.wormlight.prefab == "wormlight_light_greater" then
                    target.wormlight.components.spell.lifetime = 0
                    target.wormlight.components.spell:ResumeSpell()
                    return
                else
                    target.wormlight.components.spell:OnFinish()
                end
            end

            local light = SpawnPrefab("wormlight_light_greater")
            light.components.spell:SetTarget(target)
            if light:IsValid() then
                if light.components.spell.target == nil then
                    light:Remove()
                else
                    light.components.spell:StartSpell()
                end
            end
            if target.components.locomotor ~= nil then
                target.components.locomotor:SetExternalSpeedMultiplier(inst, "spice_tf_popping_candy", 1.25)
            end
        end,
        -- onextendedfn = function (inst,target) -- buff存在期间，添加了相同buff的执行函数
        -- end,
        ondetachedfn = function(inst, target) -- buff结束时的执行函数
            if target.components.locomotor ~= nil then
                target.components.locomotor:RemoveExternalSpeedMultiplier(inst, "spice_tf_popping_candy")
            end
        end,
    },
    -- 章鱼小丸子
    takoyaki = {
        duration = TUNING.TOTAL_DAY_TIME,     -- buff时长
        priority = 1,                         -- 优先级
        onattachedfn = function(inst, target) -- buff触发的执行函数
            if target.components.sanity then
                target:ListenForEvent("onattackother", AfterAttack)
            end
            if target.components.planardamage ~= nil then
                target.components.planardamage.externalmultipliers:SetModifier(inst, 1.5, "takoyaki")
            end
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:SetModifier(inst, 1.5)
            end
        end,
        -- onextendedfn = function (inst,target) -- buff存在期间，添加了相同buff的执行函数
        -- end,
        ondetachedfn = function(inst, target) -- buff结束时的执行函数
            if target.components.sanity then
                target:RemoveEventCallback("onattackother", AfterAttack)
            end
            if target.components.planardamage ~= nil then
                target.components.planardamage.externalmultipliers:RemoveModifier(inst, "takoyaki")
            end
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:RemoveModifier(inst)
            end
        end,
    },
    -- 榴莲糖
    durian_candy = {
        duration = TUNING.TOTAL_DAY_TIME,     -- buff时长
        priority = 1,                         -- 优先级
        onattachedfn = function(inst, target) -- buff触发的执行函数
            if target.components.planardefense ~= nil then
                target.components.planardefense:AddBonus(target, 25, "durian_combat_defense")
            end
            if target.components.health ~= nil then
                target.components.health.externalabsorbmodifiers:SetModifier(inst, 0.5)
            end
            if not target:HasTag("DurianCandy") then
                target:AddTag("DurianCandy")
            end
        end,
        -- onextendedfn = function (inst,target) -- buff存在期间，添加了相同buff的执行函数
        -- end,
        ondetachedfn = function(inst, target) -- buff结束时的执行函数
            if target.components.planardefense ~= nil then
                target.components.planardefense:RemoveBonus(target, "durian_combat_defense")
            end
            if target.components.health ~= nil then
                target.components.health.externalabsorbmodifiers:RemoveModifier(inst)
            end
            if target:HasTag("DurianCandy") then
                target:RemoveTag("DurianCandy")
            end
        end,
    },
    -- 沙拉酱
    dressing = {
        duration = 60,                        -- buff时长
        priority = 1,                         -- 优先级
        onattachedfn = function(inst, target) -- buff触发的执行函数
            inst.task = inst:DoPeriodicTask(TUNING.JELLYBEAN_TICK_RATE, OnTick, nil, target)
        end,
        onextendedfn = function(inst, target)
            inst.components.timer:StopTimer("buffover")
            inst.components.timer:StartTimer("buffover", 60)
            inst.task:Cancel()
            inst.task = inst:DoPeriodicTask(TUNING.JELLYBEAN_TICK_RATE, OnTick, nil, target)
        end,
        ondetachedfn = function(inst, target) -- buff结束时的执行函数
            inst:Remove()
        end,
    },
    -- 甜辣酱
    sweet_chili_sauce = {
        duration = TUNING.BUFF_ATTACK_DURATION,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:SetModifier(inst, 1.4)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:RemoveModifier(inst)
            end
        end,
    },
    -- 培根碎
    bacon_bits = {
        duration = 1680,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:SetModifier(inst, 1.25)
                target:ListenForEvent("onhitother", tf_bacon_bits)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:RemoveModifier(inst)
                target:RemoveEventCallback("onhitother", tf_bacon_bits)
            end
        end,
    },
    -- 咖啡粉
    coffee_powder = {
        duration = 240,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.locomotor then
                target.components.locomotor:SetExternalSpeedMultiplier(inst, "tf_buff_coffee_powder", 1.1)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.locomotor then
                target.components.locomotor:RemoveExternalSpeedMultiplier(inst, "tf_buff_coffee_powder")
            end
        end,
    },
    -- 草莓酱
    strawberry_jam = {
        duration = TUNING.TOTAL_DAY_TIME,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target:ListenForEvent("onhitother", strawberry_jam)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target:RemoveEventCallback("onhitother", strawberry_jam)
            end
        end,
    },
    -- 橘子酱
    orange_jam = {
        duration = TUNING.TOTAL_DAY_TIME,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:SetModifier(inst, 1.05)
                target:ListenForEvent("onhitother", OnHit_OrangeJam)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:RemoveModifier(inst)
                target:RemoveEventCallback("onhitother", OnHit_OrangeJam)
            end
        end,
    },
    -- 彩虹苹果:无敌3分钟
    rainbow_apple = {
        duration = 180,
        priority = 1,
        onattachedfn = function(inst, target)
            if not target:HasTag("DurianCandy") then
                target:AddTag("DurianCandy") -- 被攻击不会僵直
            end
            -- 100%吸收伤害
            if target.components.health ~= nil then
                target.components.health.externalabsorbmodifiers:SetModifier(inst, 1)
            end
        end,
        ondetachedfn = function(inst, target)
            if target:HasTag("DurianCandy") then
                target:RemoveTag("DurianCandy")
            end
            if target.components.health ~= nil then
                target.components.health.externalabsorbmodifiers:RemoveModifier(inst)
            end
        end,
    },
    -- 蛋白粉
    protein_powder = {
        duration = 960,
        priority = 1,
        onattachedfn = function(inst, target)
            if not target:HasTag("tf_strong") then
                target:AddTag("tf_strong") -- 背重物不减速
            end
        end,
        ondetachedfn = function(inst, target)
            if target:HasTag("tf_strong") then
                target:RemoveTag("tf_strong")
            end
        end,
    },
    -- 泡菜粉
    kimchi_powder = {
        duration = 960,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.health ~= nil then
                target.components.health.externalfiredamagemultipliers:SetModifier(inst, 0)
            end
            if target.components.temperature then
                inst.task = inst:DoPeriodicTask(0, function()
                    local current = target.components.temperature:GetCurrent()
                    if current < 10 then                                 -- 当前体温低于10度时
                        target.components.temperature:SetTemperature(10) -- 将温度重新设置为10
                    elseif current > 60 then                             -- 当前体温高于60度时
                        target.components.temperature:SetTemperature(60) -- 将温度重新设置为60
                    end
                end, nil, target)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.health ~= nil then
                target.components.health.externalfiredamagemultipliers:RemoveModifier(inst)
            end
            if inst.task ~= nil then
                inst.task:Cancel()
                inst.task = nil
            end
        end,
    },
    -- 不过冷
    no_clod = {
        duration = 1440,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.temperature then
                inst.task = inst:DoPeriodicTask(0, function()
                    local current = target.components.temperature:GetCurrent()
                    if current < 10 then                                 -- 当前体温低于10度时
                        target.components.temperature:SetTemperature(10) -- 将温度重新设置为10
                    end
                end, nil, target)
            end
        end,
        ondetachedfn = function(inst, target)
            if inst.task ~= nil then
                inst.task:Cancel()
                inst.task = nil
            end
        end,
    },
    -- 不过热
    no_hot = {
        duration = 1440,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.health ~= nil then
                target.components.health.externalfiredamagemultipliers:SetModifier(inst, 0)
            end
            if target.components.temperature then
                inst.task = inst:DoPeriodicTask(0, function()
                    local current = target.components.temperature:GetCurrent()
                    if current > 60 then                                 -- 当前体温高于60度时
                        target.components.temperature:SetTemperature(60) -- 将温度重新设置为60
                    end
                end, nil, target)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.health ~= nil then
                target.components.health.externalfiredamagemultipliers:RemoveModifier(inst)
            end
            if inst.task ~= nil then
                inst.task:Cancel()
                inst.task = nil
            end
        end,
    },
}

return buffs
